﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Grundy.Administration.Web.Models;
using Grundy.Administration.Web.Services;
using Grundy.Entity;
using Grundy.Common;
using Grundy.Message;

namespace Grundy.Administration.Web.Controllers
{
    [Authorize]
    public class 
        EntitlementController : Controller
    {
        private readonly EntitlementService _entitlementService;
        private readonly LicenseService _licenseService;
        private readonly NodeService _nodeService;
        private readonly CustomerService _customerService;
        private readonly FeatureService _featureService;
        private readonly ProductService _productService;
        private readonly Application _application;

        public EntitlementController(EntitlementService entitlementService, LicenseService licenseService, NodeService nodeService, CustomerService customerService, FeatureService featureService, ProductService productService, Application application)
        {
            _entitlementService = entitlementService;
            _licenseService = licenseService;
            _nodeService = nodeService;
            _customerService = customerService;
            _featureService = featureService;
            _productService = productService;
            _application = application;
        }

        public EntitlementController()
        {
            _application = Application.Instance;
            _entitlementService = new EntitlementService();
            var entitlementsDatabase = _entitlementService.Db;

            _licenseService = new LicenseService(entitlementsDatabase);
            _nodeService = new NodeService(entitlementsDatabase);
            _customerService = new CustomerService(entitlementsDatabase, _application.ServerCryptographicServicesProvider);
            _featureService = new FeatureService(entitlementsDatabase);
            _productService = new ProductService(entitlementsDatabase);
        }

        public ActionResult GetEntitlements()
        {
            var totalRecords = _entitlementService.GetEntitlements().Count();
            ViewBag.IsEmpty = totalRecords == 0;
            return View();
        }

        [HttpPost]
        public ActionResult GetEntitlementsData(int page = 1, int rows = 0)
        {
            var totalRecords = _entitlementService.GetEntitlements().Count();
            var features = _entitlementService.GetEntitlements(page, rows)
                           .Select(i => new { i.Id, CustomerName = i.Customer.Name, Products = i.LicenseEntitlements.Select(j => j.Product.Name)})
                           .ToList();

            var data = new
            {
                total = page,
                page = page,
                records = totalRecords,
                rows = features.Select((i) => new { Id = i.Id, cell = new object[] { i.Id, i.CustomerName, GetProducts(i.Products) } }).ToList()
            };

            return Json(data);
        }

        [HttpPost]
        public ActionResult GetLicenseEntitlementsDataForCustomer(string customerEntitlementId, int page = 1, int rows = 0)
        {
            int totalRecords = 0;
            var parsedCustomerEntitlementId = Guid.Parse(customerEntitlementId);
            var ce = _entitlementService.GetEntitlements().FirstOrDefault(i => i.Id == parsedCustomerEntitlementId);
            if (ce == null)
            {
                var dataEmpty = new
                {
                    total = page,
                    page = page,
                    records = totalRecords,
                    rows = new object[] { }
                };

                return Json(dataEmpty);
            }

            var licenseEntitlements = ce.LicenseEntitlements
                                      .Select(i => new { Id = i.Id, Product = i.Product.Name, License = GetLicenseSummary(i.License), Feature = i.License.Feature.Name});

            var data = new
            {
                total = page,
                page = page,
                records = totalRecords,
                rows = licenseEntitlements.Select((i) => new { Id = i.Id, cell = new object[] { i.Id, i.Product, i.License, i.Feature } }).ToList()
            };

            return Json(data);
        }

        private string GetLicenseSummary(License license)
        {
            return "{0}, {1}.".FormatWith(license.Name, license.Type);
        }

        [HttpPost]
        public ActionResult New(string customer)
        {
            var c = _customerService.GetCustomer(customer);
            if (c == null)
            {
                return Json(new object[] { false, "Customer with name {0} does not exist.".FormatWith(customer), Guid.Empty });
            }
            if (_entitlementService.GetCustomerEntitlement(c) != null)
            {
                return Json(new object[] { false, "An entitlement already exists for the customer.", Guid.Empty });                
            }
            var entitlement = _entitlementService.CreateCustomerEntitlement(c);
            return Json(new object[] { true, string.Empty, entitlement.Id });
        }

        public ActionResult GetCustomerName(Guid id)
        {
            var name = _entitlementService.GetEntitlements().First(i => i.Id == id).Customer.Name;
            return Json(name, JsonRequestBehavior.AllowGet);
        }

        public ActionResult NewLicenseEntitlement(NewLicenseEntitlementViewModel newLicenseEntitlementViewModel)
        {
            var customer = _customerService.GetCustomer(newLicenseEntitlementViewModel.Customer);
            if (customer == null)
                return Json(new object[] { false, "Cannot find a customer with name {0}.".FormatWith(newLicenseEntitlementViewModel.Customer), null});
            var ce = _entitlementService.GetCustomerEntitlement(customer);
            if(ce == null)
                return Json(new object[] { false, "Cannot find a customer entitlement for customer with name {0}.".FormatWith(newLicenseEntitlementViewModel.Customer), null});

            var result = newLicenseEntitlementViewModel.ToLicenseEntitlement(_productService, _licenseService, _nodeService);
            if (!result.Item1)
            {
                return Json(new object[] {false, result.Item2, Guid.Empty});
            }
            var created = result.Item3;
            _entitlementService.AddLicenseEntitlement(ce, created);
            return Json(new object[] { true, string.Empty, created.Id });
        }

        [HttpPost]
        public ActionResult DeleteLicenseEntitlement(string customerEntitlementId, string licenseEntitlementId)
        {
            var parsedCustomerEntitlementId = Guid.Parse(customerEntitlementId);
            var parsedLicenseEntitlementId = Guid.Parse(licenseEntitlementId);
            _entitlementService.DeleteLicenseEntitlement(parsedCustomerEntitlementId, parsedLicenseEntitlementId);
            return Json(new object[] {true, string.Empty, licenseEntitlementId});
        }
       
        [HttpPost]
        public ActionResult GetCustomerKey(string customerEntitlementId)
        {
            var parsedCustomerEntitlementId = Guid.Parse(customerEntitlementId);
            var customerEntitlement = _entitlementService.GetEntitlements().FirstOrDefault(i => i.Id == parsedCustomerEntitlementId);
            if (customerEntitlement == null)
            {
                return Json(new object[] { false, string.Empty, null});
            }
            var customerId = customerEntitlement.Customer.Id;
            var customerKey = _customerService.GetCustomerKey(customerId);
            return Json(new object[] { true, string.Empty, customerKey });            
        }

        public ActionResult GetCustomerEntitlementFile(string customerEntitlementId)
        {
            var parsedCustomerEntitlementId = Guid.Parse(customerEntitlementId);
            var licenseManager = new LicenseManager(_application.EntitlementServerCryptographicServicesProvider);
            var customerEntitlement = _entitlementService.GetEntitlements().Where(i => i.Id == parsedCustomerEntitlementId).First();
            var container = licenseManager.CreateLicenseForEntitlement(customerEntitlement);
            return File(container.Serialize().ToByteArrayUsingUtf8(), "application/glf", "{0}.entitlement.{1}.glf".FormatWith(customerEntitlement.Customer.Name.Replace(" ", "_"), Clock.Instance.Utc.ToString("dd/MMMM/yyyy")));
        }

        private string GetProducts(IEnumerable<string > products)
        {
            return string.Join(", ", products.Distinct());
        }
    }
}